package com.qn.visitor.intercept.intercept;


import com.qn.visitor.intercept.IRuleIntercept;
import inet.ipaddr.IPAddress;
import inet.ipaddr.IPAddressSegment;
import inet.ipaddr.IPAddressSeqRange;
import inet.ipaddr.IPAddressString;
import inet.ipaddr.ipv4.IPv4AddressTrie;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * qingniu-cloud user source analysis
 *
 * @Author: TXG
 * @Date: 2024/6/11
 * @Version V0.0.2
 */
public class IpAddressIntercept implements IRuleIntercept {

    @Override
    public Integer execute(String atom, List<String> rules) {
        //TODO: IP判断还需要优化 IPv4AddressTrie 需要缓存每次初始化具有一定开销
        IPv4AddressTrie blocksTriex = new IPv4AddressTrie();
        for (String ip : rules) {
            IPAddressString candidateRange = new IPAddressString(ip);
            IPAddressSeqRange range = candidateRange.getSequentialRange();
            IPAddress[] blocks= range.spanWithSequentialBlocks();
            ArrayList<IPAddress> allSplits = splitBlocks(blocks);
            for (IPAddress addr : allSplits) {
                blocksTriex.add(addr.toIPv4());
            }
        }
        IPv4AddressTrie.IPv4TrieNode containingNode = blocksTriex.elementsContaining(
                new IPAddressString(atom).getAddress().toIPv4());
        if (containingNode != null) {
            return 1;
        }
        return 0;
    }

    static ArrayList<IPAddress> splitBlocks(IPAddress[] blocks) {
        ArrayList<IPAddress> allSplits = new ArrayList<>();
        for (IPAddress block : blocks) {
            boolean isSplit = false;
            if (block.isMultiple()) {
                for (int i = 0; i < block.getSegmentCount(); i++) {
                    IPAddressSegment segment = block.getSegment(i);
                    if (segment.isMultiple()) {
                        if (segment.isFullRange()) {
                            break;
                        }
                        split(block, i, allSplits);
                        isSplit = true;
                        break;
                    }
                }
            }
            if (!isSplit) {
                allSplits.add(block);
            }
        }
        return allSplits;
    }

    static void split(IPAddress block, int index, ArrayList<IPAddress> allSplits) {
        Iterator<? extends IPAddress> iterator = block.blockIterator(index + 1);
        ArrayList<IPAddress> addrs = new ArrayList<>(block.getMaxSegmentValue() + 1);
        while (iterator.hasNext()) {
            addrs.add(iterator.next());
        }
        allSplits.addAll(addrs);
    }

}
